
//                   _ooOoo_
//                  o8888888o
//                  88" . "88
//                  (| -_- |)
//                  O\  =  /O
//               ____/`---'\____
//             .'  \\|     |//  `.
//            /  \\|||  :  |||//  \
//           /  _||||| -:- |||||-  \
//           |   | \\\  -  /// |   |
//           | \_|  ''\---/''  |   |
//           \  .-\__  `-`  ___/-. /
//         ___`. .'  /--.--\  `. . __
//      ."" '<  `.___\_<|>_/___.'  >'"".
//     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//     \  \ `-.   \_ __\ /__ _/   .-` /  /
//======`-.____`-.___\_____/___.-`____.-'======
//                   `=---='
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//         佛祖保佑       永无BUG
//  本模块已经经过开光处理，绝无可能再产生bug
//=============================================
package org.misalen.web.server.controllers.user;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.misalen.annotations.ControllerApi;
import org.misalen.annotations.InterfaceApi;
import org.misalen.web.database.model.mysql.pro.ProAdvertOrder;
import org.misalen.web.database.model.mysql.pro.ProAdvertOrderPayInfo;
import org.misalen.web.database.model.mysql.pro.ProMapAdvertising;
import org.misalen.web.database.model.mysql.pro.ProMapPayInfo;
import org.misalen.web.database.model.mysql.pro.ProWebAdvertising;
import org.misalen.web.database.model.mysql.pro.ProWebPayInfo;
import org.misalen.web.server.config.ServerUrl;
import org.misalen.web.server.controllers.BaseController;
import org.misalen.web.server.exception.CustomerException;
import org.misalen.web.server.forms.CallBackAlipayForm;
import org.misalen.web.server.result.Empty;
import org.misalen.web.server.result.WecahtCallBack;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@ControllerApi(value = "支付回调")
@RequestMapping(value = ServerUrl.UserPaybackControllerControllerUrl)
public class UserPaybackController extends BaseController {

	@RequestMapping(value = "/web/alipay", method = { RequestMethod.POST, RequestMethod.GET })
	@InterfaceApi(value = "网页广告阿里支付回调", resultClass = { Empty.class })
	public @ResponseBody String webalipay(@ModelAttribute CallBackAlipayForm form) throws Exception {
		if ("TRADE_SUCCESS".equals(form.getTrade_status()) || "TRADE_FINISHED".equals(form.getTrade_status())) {
			String out_trade_no = form.getOut_trade_no();
			// TODO 签名验证
			// Map<String, String> paramsMap = convertClazzToMap(form);
			// Map<String, String> temp = mapClearNull(paramsMap);

			// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
			ProWebPayInfo proWebPayInfo = proWebPayInfoRepository.getByWebId(out_trade_no);
			if (proWebPayInfo == null) {
				return "failure";
			}
			ProWebAdvertising proWebAdvertising = proWebAdvertisingRepository.get(ProWebAdvertising.class,
					proWebPayInfo.getWebId());
			if (proWebAdvertising == null) {
				return "failure";
			}
			// 2 如果订单存在，检验total_amount是否和订单中的一致（这里单位是元，订单中的是分）
			Double totalAmount = Double.valueOf(form.getTotal_amount());
			int total = BigDecimal.valueOf(totalAmount).multiply(new BigDecimal(100)).intValue();
			if (total != proWebAdvertising.getPromotionExpenses()) {
				return "failure";
			}
			finish(proWebAdvertising);
			logger.info("Sign success");
			return "success";
		} else {
			logger.info("Sign FAIL");
			return "failure";
		}
	}

	private void finish(ProWebAdvertising proWebAdvertising) {
		proWebAdvertising.setState("underReview");
		proWebAdvertisingRepository.update(proWebAdvertising);
	}

	@RequestMapping(value = "/order/alipay", method = { RequestMethod.POST, RequestMethod.GET })
	@InterfaceApi(value = "广告主发布广告阿里支付回调", resultClass = { Empty.class })
	public @ResponseBody String orderalipay(@ModelAttribute CallBackAlipayForm form) throws Exception {
		logger.info("广告主发布广告阿里支付回调,orderId:" + form.getOut_trade_no() + ",status:" + form.getTrade_status() + ", message:" + form.getBody());
		if ("TRADE_SUCCESS".equals(form.getTrade_status()) || "TRADE_FINISHED".equals(form.getTrade_status())) {
			String out_trade_no = form.getOut_trade_no();
			// TODO 签名验证
			// Map<String, String> paramsMap = convertClazzToMap(form);
			// Map<String, String> temp = mapClearNull(paramsMap);

			// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
			ProAdvertOrderPayInfo proAdvertOrderPayInfo = proAdvertOrderPayInfoRepository.getByOrderId(out_trade_no);
			if (proAdvertOrderPayInfo == null) {
				return "failure";
			}
			ProAdvertOrder proAdvertOrder = proAdvertOrderRepository.get(ProAdvertOrder.class,
					proAdvertOrderPayInfo.getOrderId());
			if (proAdvertOrder == null) {
				return "failure";
			}
			// 2 如果订单存在，检验total_amount是否和订单中的一致（这里单位是元，订单中的是分）
			Double totalAmount = Double.valueOf(form.getTotal_amount());
			int total = BigDecimal.valueOf(totalAmount).multiply(new BigDecimal(100)).intValue();
			if (total != proAdvertOrder.getOrderAmount()) {
				return "failure";
			}
			finishOrder(proAdvertOrder);
			logger.info("Sign success");
			return "success";
		} else {
			logger.info("Sign FAIL");
			return "failure";
		}
	}
	
	private void finishOrder(ProAdvertOrder proAdvertOrder) {
		proAdvertOrder.setState("underReview");
		proAdvertOrderRepository.update(proAdvertOrder);
	}
	
	@RequestMapping(value = "/web/webchat", method = { RequestMethod.POST })
	@InterfaceApi(value = "地图广告微信支付回调", resultClass = { Empty.class })
	public @ResponseBody WecahtCallBack webwechat(HttpServletRequest request) throws CustomerException {
		WecahtCallBack result = new WecahtCallBack();
		SortedMap<String, String> reqMap = null;
		try {
			ServletInputStream instream = request.getInputStream();
			StringBuffer sb = new StringBuffer();
			int len = -1;
			byte[] buffer = new byte[1024];
			while ((len = instream.read(buffer)) != -1) {
				sb.append(new String(buffer, 0, len));
			}
			instream.close();
			reqMap = doXMLParseWithSorted(sb.toString());// 接受微信的通知参数
			// logger.error("错误测试111：" + JSON.toJSONString(reqMap));
			// if (!wechatPayImpl.clickSign(reqMap)) {
			// logger.error("Sign FAIL : " + reqMap);
			// result.setReturn_code("FAIL");
			// result.setReturn_msg("sign fail");
			// } else {
			logger.info("SUCCESS：" + reqMap);
			result.setReturn_code("SUCCESS");
			result.setReturn_msg("OK");
			// }
		} catch (Exception e) {
			logger.error(e);
			result.setReturn_code("FAIL");
			result.setReturn_msg(e.getMessage());
		}
		// TODO 签名验证
		String out_trade_no = reqMap.get("out_trade_no").toString();
		// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
		ProWebPayInfo proWebPayInfo = proWebPayInfoRepository.get(ProWebPayInfo.class, out_trade_no);
		if (proWebPayInfo == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		ProWebAdvertising proWebAdvertising = proWebAdvertisingRepository.get(ProWebAdvertising.class,
				proWebPayInfo.getWebId());
		if (proWebAdvertising == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		if (result.getReturn_code().equals("SUCCESS")) {
			finish(proWebAdvertising);
		}
		return result;
	}

	@RequestMapping(value = "/order/webchat", method = { RequestMethod.POST })
	@InterfaceApi(value = "广告主发布广告支付回调", resultClass = { Empty.class })
	public @ResponseBody WecahtCallBack orderwechat(HttpServletRequest request) throws CustomerException {
		WecahtCallBack result = new WecahtCallBack();
		SortedMap<String, String> reqMap = null;
		try {
			ServletInputStream instream = request.getInputStream();
			StringBuffer sb = new StringBuffer();
			int len = -1;
			byte[] buffer = new byte[1024];
			while ((len = instream.read(buffer)) != -1) {
				sb.append(new String(buffer, 0, len));
			}
			instream.close();
			reqMap = doXMLParseWithSorted(sb.toString());// 接受微信的通知参数
			// logger.error("错误测试111：" + JSON.toJSONString(reqMap));
			// if (!wechatPayImpl.clickSign(reqMap)) {
			// logger.error("Sign FAIL : " + reqMap);
			// result.setReturn_code("FAIL");
			// result.setReturn_msg("sign fail");
			// } else {
			logger.info("SUCCESS：" + reqMap);
			result.setReturn_code("SUCCESS");
			result.setReturn_msg("OK");
			// }
		} catch (Exception e) {
			logger.error(e);
			result.setReturn_code("FAIL");
			result.setReturn_msg(e.getMessage());
		}
		// TODO 签名验证
		String out_trade_no = reqMap.get("out_trade_no").toString();
		// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
		ProAdvertOrderPayInfo proAdvertOrderPayInfo = proAdvertOrderPayInfoRepository.get(ProAdvertOrderPayInfo.class, out_trade_no);
		if (proAdvertOrderPayInfo == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		ProAdvertOrder proAdvertOrder = proAdvertOrderRepository.get(ProAdvertOrder.class,
				proAdvertOrderPayInfo.getOrderId());
		if (proAdvertOrder == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		if (result.getReturn_code().equals("SUCCESS")) {
			finishOrder(proAdvertOrder);
		}
		return result;
	}
	
	@RequestMapping(value = "/map/alipay", method = { RequestMethod.POST, RequestMethod.GET })
	@InterfaceApi(value = "地图广告阿里支付回调", resultClass = { Empty.class })
	public @ResponseBody String mapalipay(@ModelAttribute CallBackAlipayForm form) throws Exception {
		if ("TRADE_SUCCESS".equals(form.getTrade_status()) || "TRADE_FINISHED".equals(form.getTrade_status())) {
			String out_trade_no = form.getOut_trade_no();
			// TODO 签名验证
			// Map<String, String> paramsMap = convertClazzToMap(form);
			// Map<String, String> temp = mapClearNull(paramsMap);

			// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
			ProMapPayInfo proMapPayInfo = proMapPayInfoRepository.get(ProMapPayInfo.class, out_trade_no);
			if (proMapPayInfo == null) {
				return "failure";
			}
			ProMapAdvertising proMapAdvertising = proMapAdvertisingRepository.get(ProMapAdvertising.class,
					proMapPayInfo.getMapId());
			if (proMapAdvertising == null) {
				return "failure";
			}
			// 2 如果订单存在，检验total_amount是否和订单中的一致（这里单位是元，订单中的是分）
			Double totalAmount = Double.valueOf(form.getTotal_amount());
			int total = BigDecimal.valueOf(totalAmount).multiply(new BigDecimal(100)).intValue();
			if (total != proMapAdvertising.getPromotionExpenses()) {
				return "failure";
			}
			finish(proMapAdvertising);
			logger.info("Sign success");
			return "success";
		} else {
			logger.info("Sign FAIL");
			return "failure";
		}
	}

	@RequestMapping(value = "/map/webchat", method = { RequestMethod.POST })
	@InterfaceApi(value = "地图广告微信支付回调", resultClass = { Empty.class })
	public @ResponseBody WecahtCallBack wechat(HttpServletRequest request) throws CustomerException {
		WecahtCallBack result = new WecahtCallBack();
		SortedMap<String, String> reqMap = null;
		try {
			ServletInputStream instream = request.getInputStream();
			StringBuffer sb = new StringBuffer();
			int len = -1;
			byte[] buffer = new byte[1024];
			while ((len = instream.read(buffer)) != -1) {
				sb.append(new String(buffer, 0, len));
			}
			instream.close();
			reqMap = doXMLParseWithSorted(sb.toString());// 接受微信的通知参数
			// logger.error("错误测试111：" + JSON.toJSONString(reqMap));
			// if (!wechatPayImpl.clickSign(reqMap)) {
			// logger.error("Sign FAIL : " + reqMap);
			// result.setReturn_code("FAIL");
			// result.setReturn_msg("sign fail");
			// } else {
			logger.info("SUCCESS：" + reqMap);
			result.setReturn_code("SUCCESS");
			result.setReturn_msg("OK");
			// }
		} catch (Exception e) {
			logger.error(e);
			result.setReturn_code("FAIL");
			result.setReturn_msg(e.getMessage());
		}
		// TODO 签名验证
		String out_trade_no = reqMap.get("out_trade_no").toString();
		// 1 根据out_trade_no搜索订单，查看是否存在该订单，如果不存在，直接返回failure
		ProMapPayInfo proMapPayInfo = proMapPayInfoRepository.get(ProMapPayInfo.class, out_trade_no);
		if (proMapPayInfo == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		ProMapAdvertising proMapAdvertising = proMapAdvertisingRepository.get(ProMapAdvertising.class,
				proMapPayInfo.getMapId());
		if (proMapAdvertising == null) {
			result.setReturn_code("FAIL");
			result.setReturn_msg("订单不存在");
		}
		if (result.getReturn_code().equals("SUCCESS")) {
			finish(proMapAdvertising);
		}
		return result;
	}

	// private Map<String, String> mapClearNull(Map<String, String> paramsMap) {
	// // 必须把null去掉，不然会失败
	// Iterator<String> it = paramsMap.keySet().iterator();
	// Map<String, String> temp = new HashMap<String, String>();
	// while (it.hasNext()) {
	// String key = it.next();
	// if (paramsMap.get(key) != null) {
	// temp.put(key, paramsMap.get(key));
	// }
	// }
	// return temp;
	// }

	private void finish(ProMapAdvertising proMapAdvertising) {
		proMapAdvertising.setState("underReview");
		proMapAdvertisingRepository.update(proMapAdvertising);
	}

	// private static Map<String, String> convertClazzToMap(Object obj) throws
	// Exception {
	// Map<String, String> reMap = new HashMap<String, String>();
	// if (obj == null)
	// return null;
	// Field[] fields = obj.getClass().getDeclaredFields();
	// for (int i = 0; i < fields.length; i++) {
	// Field f = obj.getClass().getDeclaredField(fields[i].getName());
	// f.setAccessible(true);
	// Object o = f.get(obj);
	// String name = fields[i].getName();
	// if (o == null) {
	// reMap.put(name, null);
	// } else {
	// reMap.put(name, o.toString());
	// }
	// }
	// return reMap;
	// }

	@SuppressWarnings("rawtypes")
	public static SortedMap<String, String> doXMLParseWithSorted(String strxml) throws Exception {
		strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
		if (null == strxml || "".equals(strxml)) {
			return null;
		}
		SortedMap<String, String> m = new TreeMap<String, String>();
		InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
		SAXBuilder builder = new SAXBuilder();
		Document doc = builder.build(in);
		Element root = doc.getRootElement();
		List list = root.getChildren();
		Iterator it = list.iterator();
		while (it.hasNext()) {
			Element e = (Element) it.next();
			String k = e.getName();
			String v = "";
			List children = e.getChildren();
			if (children.isEmpty()) {
				v = e.getTextNormalize();
			} else {
				v = getChildrenText(children);
			}

			m.put(k, v);
		}

		// 关闭流
		in.close();
		return m;
	}

	@SuppressWarnings("rawtypes")
	public static String getChildrenText(List children) {
		StringBuffer sb = new StringBuffer();
		if (!children.isEmpty()) {
			Iterator it = children.iterator();
			while (it.hasNext()) {
				Element e = (Element) it.next();
				String name = e.getName();
				String value = e.getTextNormalize();
				List list = e.getChildren();
				sb.append("<" + name + ">");
				if (!list.isEmpty()) {
					sb.append(getChildrenText(list));
				}
				sb.append(value);
				sb.append("</" + name + ">");
			}
		}
		return sb.toString();
	}
}
